package com.syni.mdd.sjb.community.base.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.syni.mdd.sjb.common.component.mybatis.community.entity.*;
import com.syni.mdd.sjb.common.component.mybatis.community.mapper.SjbQywxChatGroupInfoMapper;
import com.syni.mdd.sjb.common.component.mybatis.vo.PageResultVO;
import com.syni.mdd.sjb.common.component.utils.common.exception.BusinessException;
import com.syni.mdd.sjb.common.component.utils.common.utils.BeanUtils;
import com.syni.mdd.sjb.common.component.utils.common.utils.ResultMapHelper;
import com.syni.mdd.sjb.common.component.utils.common.utils.StringUtils;
import com.syni.mdd.sjb.community.base.constants.Constants;
import com.syni.mdd.sjb.community.base.entity.dto.PageDTO;
import com.syni.mdd.sjb.community.base.entity.vo.QywxChatListVO;
import com.syni.mdd.sjb.community.base.entity.vo.QywxGroupChatInfoVO;
import com.syni.mdd.sjb.community.base.entity.vo.QywxGroupChatListVO;
import com.syni.mdd.sjb.community.base.entity.vo.QywxMemberListVO;
import com.syni.mdd.sjb.community.base.service.*;
import com.syni.mdd.sjb.community.base.utils.CommonBeanUtils;
import com.syni.mdd.sjb.community.base.utils.MybatisUtils;
import com.syni.mdd.sjb.community.base.utils.OAUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author wangbaitao
 * @version 1.0.0
 * <h>数据宝企业微信群聊信息表 service impl</h>
 * @Date 2021/2/22
 **/
@Service
@Transactional
public class SjbQywxChatGroupInfoServiceImpl extends ServiceImpl<SjbQywxChatGroupInfoMapper, SjbQywxChatGroupInfo>
        implements SjbQywxChatGroupInfoService {
    @Autowired
    private SjbQywxChatGroupRefService sjbQywxChatGroupRefService;
    @Autowired
    private SjbQywxAdminService sjbQywxAdminService;
    @Autowired
    private SjbQywxExternalUserInfoService sjbQywxExternalUserInfoService;
    @Autowired
    private SjbQywxCompanyUserService sjbQywxCompanyUserService;
    @Autowired
    private SjbChatCountDetailsService sjbChatCountDetailsService;
    /**
     * 类型：1-企业成员
     */
    private static final String TYPE_COMPANY = "1";
    private static final String USER_TYPE_OWNER = "0";
    private static final String USER_TYPE_COMPANY = "1";
    private static final String USER_TYPE_WECHAT = "2";
    private static final String USER_TYPE_QYWX = "3";

    /**
     * 根据企业id（corpId）进行群聊信息的同步，默认是获取该企业在应用范围内的全量数据
     * <pre>
     *     1、调用api接口，获取群聊列表(先根据cropId进行数据清除)
     *     2、根据chat_id调用企业微信api获取详情接口，根据返回结果进行group_chat的加工
     *     3、根据member_list进行ref表的加工，首先需要获取对应的oldRefs数据，这是为了加工是否离群的状态
     * </pre>
     *
     * @param corpId 企业id
     * @return 同步结果
     */
    @Override
    public Map<String, Object> syncData(String corpId) {
        //获取群聊列表数据
        LocalDateTime syncTime = LocalDateTime.now();
        List<QywxChatListVO> groupLists = new ArrayList<>();
        //获取群聊列表
        produceGroupList(corpId, "", groupLists);
        if (!groupLists.isEmpty()) {
            //进行群聊Info数据的清除
            remove(new QueryWrapper<SjbQywxChatGroupInfo>().eq(SjbQywxChatGroupInfo.CORP_ID, corpId));
            //进行groupChatInfo和ref表数据的加工
            produceGroupInfoAndRef(groupLists, corpId, syncTime);
        }
        return ResultMapHelper.success(null, "同步成功");
    }

    /**
     * 社群管理列表查询接口
     * <pre>
     *     1、查找chat_info表获取基本数据
     *     2、根据chat_id进行ref表的数据查询，用于加工Member_list
     *     3、进行统计数据的加工
     * </pre>
     *
     * @param pageDTO 查询对象dto
     * @return 查询结果
     */
    @Override
    public Map<String, Object> queryDataByParam(PageDTO pageDTO) {
        Page<SjbQywxChatGroupInfo> page = new Page<>(pageDTO.getPageNo(), pageDTO.getPageSize());
        IPage<SjbQywxChatGroupInfo> groupInfoIPage = page(page, getQueryWrapper(pageDTO));
        if (!groupInfoIPage.getRecords().isEmpty()) {
            //进行其他数据的加工
            List<SjbQywxChatGroupInfo> groupInfos = groupInfoIPage.getRecords();
            Set<String> ownerIds = groupInfos.stream().map(SjbQywxChatGroupInfo::getOwner).collect(Collectors.toSet());
            //获取群主名称,这里必然是企业员工
            List<SjbQywxAdmin> qywxAdmins = sjbQywxAdminService.list(new QueryWrapper<SjbQywxAdmin>()
                    .in(SjbQywxAdmin.USERID, ownerIds).eq(SjbQywxAdmin.CORPID, pageDTO.getCorpId()));
            Map<String, SjbQywxAdmin> qywxAdminMap = qywxAdmins.stream().collect(Collectors
                    .toMap(SjbQywxAdmin::getUserid, Function.identity()));
            //获取相关的ref表数据
            Set<String> chatIds = groupInfos.stream().map(SjbQywxChatGroupInfo::getChatId).collect(Collectors.toSet());
            List<SjbQywxChatGroupRef> groupRefs = sjbQywxChatGroupRefService.list(new QueryWrapper<SjbQywxChatGroupRef>()
                    .in(SjbQywxChatGroupRef.CHAT_ID, chatIds));
            Map<String, List<SjbQywxChatGroupRef>> groupRefMap = groupRefs.stream().collect(Collectors
                    .groupingBy(SjbQywxChatGroupRef::getChatId));
            //获取外部联系人的相关数据集合
            Set<String> userIds = groupRefs.stream().map(SjbQywxChatGroupRef::getUserid).collect(Collectors.toSet());
            List<SjbQywxExternalUserInfo> userInfos = sjbQywxExternalUserInfoService
                    .list(new QueryWrapper<SjbQywxExternalUserInfo>().in(SjbQywxExternalUserInfo.EXTERNAL_USER_ID,
                            userIds));
            Map<String, SjbQywxExternalUserInfo> userInfoMap = new HashMap<>();
            Map<String, String> userNameMap = new HashMap<>();
            //进行数据的覆盖
            userInfos.forEach(userInfo -> {
                userInfoMap.put(userInfo.getExternalUserid(), userInfo);
                userNameMap.put(userInfo.getExternalUserid(), userInfo.getName());
            });
            //获取名称map，这里需要对corpId进行优化
            if (StringUtils.isBlank(pageDTO.getCorpId())) {
                pageDTO.setCorpId(groupInfoIPage.getRecords().get(0).getCorpId());
            }
            List<SjbQywxCompanyUser> companyUsers = sjbQywxCompanyUserService.list(new QueryWrapper<SjbQywxCompanyUser>()
                    .eq(SjbQywxCompanyUser.CORP_ID, pageDTO.getCorpId()));
            companyUsers.forEach(companyUser -> userNameMap.put(companyUser.getUserid(), companyUser.getName()));
            //获取群聊统计数据
            List<SjbChatCountDetails> chatCountDetails = sjbChatCountDetailsService
                    .list(new QueryWrapper<SjbChatCountDetails>().eq(SjbChatCountDetails.CORP_ID, pageDTO.getCorpId())
                            .eq(SjbChatCountDetails.STAT_TIME, LocalDate.now().minusDays(1)));
            Map<String, SjbChatCountDetails> chatCountDetailsMap = chatCountDetails.stream().collect(Collectors
                    .toMap(SjbChatCountDetails::getChatId, Function.identity()));
            //进行数据的加工
            AtomicInteger groupUserCounts = new AtomicInteger(0);
            groupInfos.forEach(groupInfo -> {
                if (Objects.nonNull(qywxAdminMap.get(groupInfo.getOwner()))) {
                    groupInfo.setOwnerName(qywxAdminMap.get(groupInfo.getOwner()).getName());
                }
                //进行userInfos的处理,同时进行chatCount的统计
                //企业成员数据统计
                AtomicInteger companyCounts = new AtomicInteger(0);
                if (Objects.nonNull(groupRefMap.get(groupInfo.getChatId()))) {
                    groupUserCounts.addAndGet(groupRefMap.get(groupInfo.getChatId()).size());
                    groupInfo.setSize(groupRefMap.get(groupInfo.getChatId()).size());
                    //进行userInfo的处理
                    groupRefMap.get(groupInfo.getChatId()).forEach(groupRef -> {
                        groupRef.setName(userNameMap.get(groupRef.getUserid()));
                        if (TYPE_COMPANY.equals(groupRef.getType())) {
                            companyCounts.addAndGet(1);
                            //企业成员，判断是否是群主
                            if (groupInfo.getOwner().equals(groupRef.getUserid())) {
                                groupRef.setUserType(USER_TYPE_OWNER);
                            } else {
                                groupRef.setUserType(USER_TYPE_COMPANY);
                            }
                        } else {
                            //判断外部联系人的类型
                            if (Objects.nonNull(userInfoMap.get(groupRef.getUserid()))) {
                                groupRef.setUserType(String.valueOf(Integer.parseInt(userInfoMap.get(groupRef
                                        .getUserid()).getType()) + 1));
                            }
                        }
                    });
                    SjbChatCountDetails sjbChatCountDetails = chatCountDetailsMap.get(groupInfo.getChatId());
                    if (Objects.isNull(sjbChatCountDetails)) {
                        sjbChatCountDetails = new SjbChatCountDetails();
                        sjbChatCountDetails.setChatId(groupInfo.getChatId());
                    }
                    sjbChatCountDetails.setRemark(companyCounts.get() + "名企业成员");
                    groupInfo.setCountArr(sjbChatCountDetails);
                    //进行UserInfos的赋值
                    groupInfo.setUserInfos(groupRefMap.get(groupInfo.getChatId()));
                }
                //进行统计数据的处理
            });
            return ResultMapHelper.success(PageResultVO.builder().records(groupInfos)
                    .pageNo(groupInfoIPage.getCurrent())
                    .pageSize(groupInfoIPage.getSize())
                    .totalPages(groupInfoIPage.getPages())
                    .totalElements(groupInfoIPage.getTotal())
                    .groupCounts(groupInfos.size())
                    .groupUserCounts(groupUserCounts.get())
                    .build(), "获取成功", true);
        }
        return ResultMapHelper.failure("没有符合条件的数据");
    }

    /**
     * 根据chatId进行群聊信息的查询
     *
     * @param chatId 群聊Id
     * @return 查询结果
     */
    @Override
    public Map<String, Object> getChatDataById(String chatId) {
        if (StringUtils.isBlank(chatId)) {
            throw new BusinessException("业务异常：请输入群聊id");
        }
        PageDTO pageDTO = PageDTO.builder().pageNo(1L).pageSize(1L).chatId(chatId).build();
        Map<String, Object> result = queryDataByParam(pageDTO);
        Object data = result.get("data");
        if (Objects.nonNull(data)) {
            PageResultVO pageResultVO = (PageResultVO) data;
            if (!pageResultVO.getRecords().isEmpty()) {
                return ResultMapHelper.success(pageResultVO.getRecords().get(0), "获取成功", true);
            }
        }
        return ResultMapHelper.success(null, "获取成功", true);
    }

    /**
     * 根据企业id获取群主信息集合
     *
     * @param corpId 企业id
     * @return 查询结果
     */
    @Override
    public Map<String, Object> getOwnerNames(String corpId) {
        List<SjbQywxChatGroupInfo> groupInfos = list(new QueryWrapper<SjbQywxChatGroupInfo>()
                .eq(SjbQywxChatGroupInfo.CORP_ID, corpId));
        Map<String, String> result = new HashMap<>();
        if (!groupInfos.isEmpty()) {
            Set<String> userIds = groupInfos.stream().map(SjbQywxChatGroupInfo::getOwner).collect(Collectors.toSet());
            List<SjbQywxAdmin> qywxAdmins = sjbQywxAdminService.list(new QueryWrapper<SjbQywxAdmin>()
                    .in(SjbQywxAdmin.USERID, userIds));
            qywxAdmins.forEach(admin -> result.put(admin.getUserid(), admin.getName()));
        }
        return ResultMapHelper.success(result, "获取成功", true);
    }

    /**
     * 获取queryWrapper对象
     *
     * @param pageDTO 条件对象dto
     * @return QueryWrapper
     */
    private QueryWrapper<SjbQywxChatGroupInfo> getQueryWrapper(PageDTO pageDTO) {
        QueryWrapper<SjbQywxChatGroupInfo> queryWrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(pageDTO.getChatId())) {
            queryWrapper.eq(SjbQywxChatGroupInfo.CHAT_ID, pageDTO.getChatId());
        }
        if (StringUtils.isNotBlank(pageDTO.getCorpId())) {
            queryWrapper.eq(SjbQywxChatGroupInfo.CORP_ID, pageDTO.getCorpId());
        }
        if (Objects.nonNull(pageDTO.getOwnerIds()) && !pageDTO.getOwnerIds().isEmpty()) {
            queryWrapper.in(SjbQywxChatGroupInfo.OWNER, pageDTO.getOwnerIds());
        }
        if (StringUtils.isNotBlank(pageDTO.getChatStatus())) {
            queryWrapper.eq(SjbQywxChatGroupInfo.STATUS, pageDTO.getChatStatus());
        }
        if (StringUtils.isNotBlank(pageDTO.getName())) {
            queryWrapper.eq(SjbQywxChatGroupInfo.NAME, pageDTO.getName());
        }
        if (StringUtils.isNotBlank(pageDTO.getCreateTimeBegin()) || StringUtils.isNotBlank(pageDTO.getCreateTimeEnd())) {
            //起始和结束时间
            queryWrapper.between(SjbQywxChatGroupInfo.CREATE_TIME,
                    MybatisUtils.getBeginDay(pageDTO.getCreateTimeBegin()),
                    MybatisUtils.getEndDay(pageDTO.getCreateTimeEnd()));
        }
        return queryWrapper;
    }

    /**
     * 进行groupChatInfo和ref表数据的加工
     * 该方法可能会对chatRef表进行大量数据的同时更新，后期有必要可以进行数据分段update(后期需求可能会存在事务占用的问题)
     *
     * @param groupLists 群聊列表集合
     * @param corpId     企业id
     * @param syncTime   同步时间
     */
    private void produceGroupInfoAndRef(List<QywxChatListVO> groupLists, String corpId, LocalDateTime syncTime) {
        //进行groupInfo的删除
        Set<String> chatIds = groupLists.stream().map(QywxChatListVO::getChatId).collect(Collectors.toSet());
        //获取oldRefs
        List<SjbQywxChatGroupRef> oldRefs = sjbQywxChatGroupRefService.list(new QueryWrapper<SjbQywxChatGroupRef>()
                .in(SjbQywxChatGroupRef.CHAT_ID, chatIds));
        Map<String, SjbQywxChatGroupRef> oldRefMap = new HashMap<>();
        oldRefs.forEach(ref -> oldRefMap.put(ref.getChatId() + ref.getUserid(), ref));
        List<SjbQywxChatGroupInfo> groupInfos = new ArrayList<>(groupLists.size());
        List<SjbQywxChatGroupRef> groupRefs = new ArrayList<>();
        groupLists.forEach(groupList -> {
            //调用企业微信api获取info数据
            JSONObject jsonObj = OAUtils.getChatInfoById(CommonBeanUtils.getToken(corpId), groupList.getChatId());
            if (Objects.equals(Constants.QYWX_OK, jsonObj.getInteger(Constants.ERROR_CODE))) {
                //进行groupInfo的数据加工
                QywxGroupChatInfoVO groupChatInfoVO = jsonObj.getObject(Constants.GROUP_CHAT, QywxGroupChatInfoVO.class);
                SjbQywxChatGroupInfo groupInfo = new SjbQywxChatGroupInfo();
                BeanUtils.copyProperties(groupChatInfoVO, groupInfo);
                groupInfo.setSyncTime(syncTime);
                groupInfo.setCreateTime(LocalDateTime.ofEpochSecond(groupChatInfoVO.getCreate_time(), 0,
                        ZoneOffset.ofHours(8)));
                groupInfo.setChatId(groupChatInfoVO.getChat_id());
                groupInfo.setMemberList(groupChatInfoVO.getMember_list());
                groupInfo.setCorpId(corpId);
                groupInfo.setStatus(groupList.getStatus());
                groupInfos.add(groupInfo);
                //进行member_list的加工
                produceGroupRef(oldRefMap, groupChatInfoVO.getMember_list(), groupChatInfoVO.getChat_id(), syncTime, corpId);
            } else {
                throw new BusinessException("业务异常，获取客户群聊详情数据失败:" + jsonObj.getString(Constants.ERROR_MSG));
            }
        });
        oldRefMap.forEach((key, value) -> groupRefs.add(value));
        //设置离群
        groupRefs.forEach(ref -> {
            ref.setStatus(!ref.getIsSync());
            ref.setSyncTime(syncTime);
        });
        //进行数据的更新
        saveBatch(groupInfos);
        sjbQywxChatGroupRefService.saveOrUpdateBatch(groupRefs);
    }

    /**
     * 进行群聊ref数据的加工
     *
     * @param oldRefMap  oldRefMap
     * @param memberList memberList
     * @param chatId     群聊id
     */
    private void produceGroupRef(Map<String, SjbQywxChatGroupRef> oldRefMap, String memberList, String chatId,
                                 LocalDateTime syncTime, String corpId) {
        List<QywxMemberListVO> memberListVOS = JSONArray.parseArray(memberList, QywxMemberListVO.class);
        memberListVOS.forEach(member -> {
            SjbQywxChatGroupRef groupRef = oldRefMap.get(chatId + member.getUserid());
            if (Objects.isNull(groupRef)) {
                groupRef = new SjbQywxChatGroupRef();
            }
            BeanUtils.copyProperties(member, groupRef);
            groupRef.setCorpid(corpId);
            groupRef.setChatId(chatId);
            groupRef.setJoinTime(LocalDateTime.ofEpochSecond(member.getJoin_time(), 0,
                    ZoneOffset.ofHours(8)));
            groupRef.setJoinScene(member.getJoin_scene());
            groupRef.setSyncTime(syncTime);
            groupRef.setIsSync(true);
            oldRefMap.put(chatId + member.getUserid(), groupRef);
        });
    }

    /**
     * 进行群聊列表数据的加工
     *
     * @param corpId     企业id
     * @param cursor     游标
     * @param groupLists 加工对象
     */
    private void produceGroupList(String corpId, String cursor, List<QywxChatListVO> groupLists) {
        JSONObject jsonObj = OAUtils.queryCompanyGroupInfos(CommonBeanUtils.getToken(corpId), 0,
                null, cursor, corpId, 1);
        if (Objects.equals(Constants.QYWX_OK, jsonObj.getInteger(Constants.ERROR_CODE))) {
            //进行数据加工,获取列表
            String groupListStr = jsonObj.getString(Constants.GROUP_CHAT_LIST);
            List<QywxGroupChatListVO> chatListVOS = JSONArray.parseArray(groupListStr, QywxGroupChatListVO.class);
            if (!chatListVOS.isEmpty()) {
                cursor = jsonObj.getString(Constants.NEXT_CURSOR);
                chatListVOS.forEach(chatListVO -> {
                    //获取列表对象
                    QywxChatListVO groupList = new QywxChatListVO();
                    groupList.setChatId(chatListVO.getChat_id());
                    groupList.setStatus(chatListVO.getStatus());
                    groupLists.add(groupList);
                });
                if (StringUtils.isNotBlank(cursor)) {
                    produceGroupList(corpId, cursor, groupLists);
                }
            }
        } else {
            throw new BusinessException("业务异常，获取群聊列表数据失败:" + jsonObj.getString(Constants.ERROR_MSG));
        }
    }
}
